package com.nfcpay;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

import android.R.string;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class CompradorActivity extends Activity implements CreateNdefMessageCallback{
	private static final String TAG = "compradorActivity";
	
	NfcAdapter mNfcAdapter;
	PendingIntent nfcPendingIntent;
	private ProgressBar mEscutando;
	private TextView 	mReciboComprador;
	private Button		mAssinar;
	private Bundle 		mBundleMsg;
	private String 		mReciboAssinado;
	private String 		mMsg = null;
	private boolean		isAssinado = false;
	private byte[] 		assinatura;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		Log.i(TAG, "[ACTIVITY] onCreate");
		super.onCreate(savedInstanceState);
		this.mBundleMsg = this.getIntent().getExtras();
		//TODO conferir
		if(mBundleMsg != null){
			mMsg = mBundleMsg.getString("msg");
		}
		setContentView(R.layout.comprador);
		
		//setando widgets
		mEscutando = (ProgressBar) findViewById(R.id.progressBarComprador);
		mReciboComprador = (TextView) findViewById(R.id.tReciboComprador);
		mAssinar = (Button) findViewById(R.id.bAssinar);
		
		// Verifica por NFC disponível
		mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
		if(mNfcAdapter == null){
			Toast.makeText(this, "NFC não está disponível", Toast.LENGTH_LONG).show();
			finish();
			return;
		}
		
		//Registra callBack
		mNfcAdapter.setNdefPushMessageCallback(this, this);
        nfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, this.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
	}
	@Override
	protected void onStart() {
		Log.i(TAG, "[ACTIVITY] onStart");
		super.onStart();
	}
	
	/**
	 * método responsável por receber, verificar, validar e assinar registro de compra
	 */
	@Override
	protected void onResume() {
		Log.i(TAG, "[ACTIVITY] onResume");
		super.onResume();
		//verifica se a msg foi setada
		if(mMsg!=null){
			//setando widgets da tela
			mEscutando.setVisibility(mEscutando.INVISIBLE);
			mReciboComprador.setVisibility(mReciboComprador.VISIBLE);
			mAssinar.setVisibility(mAssinar.VISIBLE);
			//setando recibo do comprador
			mReciboComprador.setText(mMsg);
		}
		
		//TODO retirar
//		if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())){
//			processIntent(getIntent());
//			Intent intent = getIntent();
//			Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
//		}
	     // only one message sent during the beam
	    // NdefMessage msg = (NdefMessage) rawMsgs[0];
	     // record 0 contains the MIME type, record 1 is the AAR, if present
	     //mReciboComprador.setText(new String(msg.getRecords()[0].getPayload()));
	}
	
	public void enableForegroundMode() {
        Log.d(TAG, "enableForegroundMode");

        // foreground mode gives the current active application priority for reading scanned tags
        IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); // filter for tags
        IntentFilter[] writeTagFilters = new IntentFilter[] {tagDetected};
        mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null);
	}

	public void disableForegroundMode() {
	    Log.d(TAG, "disableForegroundMode");
	
	    mNfcAdapter.disableForegroundDispatch(this);
	}
    
    /**
     * método responsável por assinar recibo
     * @throws Exception 
     */
    public void assinarRecibo(View view) throws Exception{
    	if(mReciboComprador!=null && isAssinado==false){
    		assinatura = assinarRecibo();
    		mReciboAssinado = mReciboComprador.getText().toString();
    		if(assinatura != null){
    			isAssinado = true;
    			mAssinar.setVisibility(mAssinar.INVISIBLE);
    		}
    	}
    }

    @Override
    public void onNewIntent(Intent intent) { // this method is called when an NFC tag is scanned
    	Log.d(TAG, "onNewIntent");
    	// check for NFC related actions
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
            mReciboComprador.setText("Hello NFC tag!");
        } else {
            // ignore
        }
    
        // check for NFC related actions
//        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
//            TextView textView = (TextView) findViewById(R.id.title);
//            textView.setText("Hello NFC tag!");
//        } else {
//            // ignore
//        }
    }
	
	 /**
	  * Parses the NDEF Message from the intent and prints to the TextView
	  */
	 void processIntent(Intent intent) {
		 mReciboComprador.setVisibility(mReciboComprador.VISIBLE);
	     Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
	             NfcAdapter.EXTRA_NDEF_MESSAGES);
	     // only one message sent during the beam
	     NdefMessage msg = (NdefMessage) rawMsgs[0];
	     // record 0 contains the MIME type, record 1 is the AAR, if present
	     String teste = new String(msg.getRecords()[0].getPayload());
	     mReciboComprador.setText(teste);
	     mEscutando.setVisibility(mEscutando.INVISIBLE);
	 }
	@Override
	public NdefMessage createNdefMessage(NfcEvent event) {
		if(isAssinado){
			String text = "comprador;"+mReciboComprador.getText().toString();
			NdefRecord reciboRecord = new NdefRecord(
					NdefRecord.TNF_MIME_MEDIA,
					"application/vnd.com.nfcpay".getBytes(Charset.forName("US-ASCII")),
					new byte[0],
					text.getBytes(Charset.forName("US-ASCII")));
			
			NdefRecord appRecord = NdefRecord.createApplicationRecord("com.nfcpay");
			
			NdefRecord assinaturaRecord = new NdefRecord(
					NdefRecord.TNF_MIME_MEDIA,
					"application/vnd.com.nfcpay".getBytes(Charset.forName("US-ASCII")),
					new byte[0],
					assinatura);
			
			NdefMessage msg = new NdefMessage(new NdefRecord[] {
					reciboRecord, appRecord, assinaturaRecord});
			return msg;
		}else{
			return null;
		}
	}

	public byte[] assinarRecibo() throws NoSuchAlgorithmException, InvalidKeyException{
		//obtendo a chave privada do arquivo
		Environment.getExternalStorageState();
		File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
		File dir1 = Environment.getExternalStorageDirectory();
		File privKeyDer = new File(dir, "privatekey.der");
		byte[] encodedKey = new byte[(int)privKeyDer.length()];
		
		//criando fileInputStream chavePrivada
		try {
			FileInputStream fis = new FileInputStream(privKeyDer);
			fis.read(encodedKey);
			fis.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		KeyFactory kf = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = null;
		try {
			privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
		} catch (InvalidKeySpecException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		//Algoritmo utilizado para o hash e para a criptografia - SHA1 seguido de RSA
		Signature sig = Signature.getInstance("SHA1WithRSA");
		//Atribuindo a chave privada na assinatura
		sig.initSign(privateKey);
		
		try {
			//dados da mensagem a serem assinados
			sig.update(mReciboComprador.toString().getBytes());
		} catch (SignatureException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		byte[] signature = null;
		try {
			//retorna a assinatura da mensagem em array de byte
			signature = sig.sign();
		} catch (SignatureException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//TODO inicio verificação
		//Obtendo o certificado digital do arquivo
		File certPub = new File(dir, "cert.der");
		byte[] encodedCert = new byte[(int) certPub.length()];
		
		//TODO retirar
		//criando fileInputStream certificado
		FileInputStream fisCert = null;
		String teste = null;
		try {
			fisCert = new FileInputStream(certPub);
			fisCert.read(encodedCert);
			teste = fisCert.toString();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		ByteArrayInputStream bis = new ByteArrayInputStream(encodedCert);
		Certificate c = null;
		try {
			//obtendo fábrica de certificados X.509
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			//Gerando objeto Certificate com o inputStream do arquivo
			c = cf.generateCertificate(bis);
			fisCert.close();
		} catch (CertificateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//Atribuindo a chave pública na assinatura
		sig.initVerify(c.getPublicKey());
		boolean ok = false;
		try {
			//dados da mensagem a serem verificados
			sig.update(mReciboComprador.toString().getBytes());
			//verificando assinatura
			ok = sig.verify(signature);
		} catch (SignatureException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return signature;
	}

}
